{
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  },
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "### 2-D Vectors\n",
      "\n",
      "This notebook contains example code from [*Fluent Python*](http://shop.oreilly.com/product/0636920032519.do), by Luciano Ramalho.\n",
      "\n",
      "Code by Luciano Ramalho, modified by Allen Downey.\n",
      "\n",
      "MIT License: https://opensource.org/licenses/MIT"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This example demonstrates how a user-defined type can emulate a numeric type by providing special methods.\n",
      "\n",
      "`Vector` represents a 2-D Euclidean vector:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "from math import hypot\n",
      "\n",
      "class Vector:\n",
      "\n",
      "    def __init__(self, x=0, y=0):\n",
      "        self.x = x\n",
      "        self.y = y\n",
      "\n",
      "    def __repr__(self):\n",
      "        return 'Vector(%r, %r)' % (self.x, self.y)\n",
      "\n",
      "    def __abs__(self):\n",
      "        return hypot(self.x, self.y)\n",
      "\n",
      "    def __bool__(self):\n",
      "        return bool(abs(self))\n",
      "\n",
      "    def __add__(self, other):\n",
      "        x = self.x + other.x\n",
      "        y = self.y + other.y\n",
      "        return Vector(x, y)\n",
      "\n",
      "    def __mul__(self, scalar):\n",
      "        return Vector(self.x * scalar, self.y * scalar)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Because `Vector` provides `__add__`, we can use the `+` operator to add Vectors."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "v1 = Vector(2, 4)\n",
      "v2 = Vector(2, 1)\n",
      "v1 + v2"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "And because it provides `__abs__`, we can use the built-in method `abs`.  For Euclidean vectors, the \"absolute value\" is the magnitude; for 2-D vectors, the magnitude is the hypoteneuse of the two components:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "v = Vector(3, 4)\n",
      "abs(v)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "`Vector` provides `__mul__`, so we can use the `*` operator."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "v * 3"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "But `__mul__` only supports scalar multiplication.\n",
      "\n",
      "**Exercise** What happens if you try to multiply two vectors?"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Solution goes here"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "`Vector` defines `__repr__`, which returns a string representation of the object:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "repr(v)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Because `Vector` does not provide `__str__`, Python uses `__repr__`:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "str(v)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "So what's the difference?  `str` is meant to return a human-readable representation of the object.  `repr` should return a string that can be evaluated to re-create the object.\n",
      "\n",
      "If the same representation can perform both roles, you can just define `__repr__`."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "`Vector` implements `__bool__`, so it can be used in a context where it has to be converted to `boolean`:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "if v:\n",
      "    print(v)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "If the magnitude is 0, the Vector is considered `False`:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "if Vector(0, 0):\n",
      "    print(\"Won't happen.\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "**Exercise** Create a class called `SubVector` that extends `Vector` and provides `__sub__`.  Test that you can use the `-` operator with `SubVector`.\n",
      "\n",
      "What happens if you subtract a `Vector` from a `SubVector`?  How about the other way around?"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Solution goes here"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Solution goes here"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Solution goes here"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Solution goes here"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": null
    }
   ],
   "metadata": {}
  }
 ]
}